1 module features.msvclinker; 2 public import feature; 3 import commons; 4 5 ///Feature which gets the msvclinker 6 Feature MSVCLinker; 7 8 version(Posix) 9 { 10 void initialize(){} 11 void start(){} 12 } 13 else version(Windows): 14 15 16 pragma(lib, "ole32.lib"); 17 pragma(lib, "oleaut32.lib"); 18 bool hasMSVCLinker(ref Terminal t, TargetVersion v, out ExistenceStatus where) 19 { 20 import core.sys.windows.winbase; 21 import core.sys.windows.winnt; 22 import core.sys.windows.com; 23 import core.sys.windows.wtypes; 24 import std.windows.registry; 25 immutable supportedPre2017Versions = ["14.0"]; 26 const GUID iid_SetupConfiguration = { 0x177F0C4A, 0x1CD3, 0x4DE7, [ 0xA3, 0x2C, 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D ] }; 27 28 static interface ISetupInstance : IUnknown 29 { 30 // static const GUID iid = uuid("B41463C3-8866-43B5-BC33-2B0676F7F42E"); 31 static const GUID iid = { 0xB41463C3, 0x8866, 0x43B5, [ 0xBC, 0x33, 0x2B, 0x06, 0x76, 0xF7, 0xF4, 0x2E ] }; 32 33 int GetInstanceId(BSTR* pbstrInstanceId); 34 int GetInstallDate(LPFILETIME pInstallDate); 35 int GetInstallationName(BSTR* pbstrInstallationName); 36 int GetInstallationPath(BSTR* pbstrInstallationPath); 37 int GetInstallationVersion(BSTR* pbstrInstallationVersion); 38 int GetDisplayName(LCID lcid, BSTR* pbstrDisplayName); 39 int GetDescription(LCID lcid, BSTR* pbstrDescription); 40 int ResolvePath(LPCOLESTR pwszRelativePath, BSTR* pbstrAbsolutePath); 41 } 42 43 static interface IEnumSetupInstances : IUnknown 44 { 45 // static const GUID iid = uuid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848"); 46 47 int Next(ULONG celt, ISetupInstance* rgelt, ULONG* pceltFetched); 48 int Skip(ULONG celt); 49 int Reset(); 50 int Clone(IEnumSetupInstances* ppenum); 51 } 52 53 static interface ISetupConfiguration : IUnknown 54 { 55 // static const GUID iid = uuid("42843719-DB4C-46C2-8E7C-64F1816EFD5B"); 56 static const GUID iid = { 0x42843719, 0xDB4C, 0x46C2, [ 0x8E, 0x7C, 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B ] }; 57 58 int EnumInstances(IEnumSetupInstances* ppEnumInstances) ; 59 int GetInstanceForCurrentProcess(ISetupInstance* ppInstance); 60 int GetInstanceForPath(LPCWSTR wzPath, ISetupInstance* ppInstance); 61 } 62 63 64 if("VSINSTALLDIR" in environment && !("LDC_VSDIR_FORCE" in environment)) 65 { 66 if(!("VSCMD_ARG_TGT_ARCH" in environment)) 67 return true; 68 string tgtArch = environment["VSCMD_ARG_TGT_ARCH"]; 69 if(tgtArch == "x64" || tgtArch == "x32") 70 return true; 71 } 72 if("LDC_VSDIR" in environment && std.file.exists(environment["LDC_VSDIR"])) 73 return true; 74 75 bool detectVSInstallDirViaCOM() 76 { 77 import core.sys.windows.windows; 78 import core.stdc.wchar_:wcscmp; 79 80 CoInitialize(null); scope(exit) CoUninitialize(); 81 82 ISetupConfiguration setup; 83 IEnumSetupInstances instances; 84 ISetupInstance instance; 85 DWORD fetched; 86 87 HRESULT hr = CoCreateInstance(&iid_SetupConfiguration, null, CLSCTX_ALL, &ISetupConfiguration.iid, cast(void**) &setup); 88 if(hr != S_OK || !setup) return false; 89 90 scope(exit) setup.Release(); 91 if(setup.EnumInstances(&instances) != S_OK) 92 return false; 93 scope(exit) instances.Release(); 94 95 BSTR thisVersionString, thisInstallDir; 96 while (instances.Next(1, &instance, &fetched) == S_OK && fetched) 97 { 98 if(instance.GetInstallationVersion(&thisVersionString) != S_OK || 99 instance.GetInstallationPath(&thisInstallDir) != S_OK) 100 continue; 101 return true; 102 } 103 return false; 104 } 105 106 if(detectVSInstallDirViaCOM()) 107 return true; 108 109 if(Key k = windowsGetKeyWithPath("SOFTWARE", "Microsoft", "VisualStudio", "SxS", "VS7")) 110 if(k.getValue("15.0").value_SZ) 111 return true; 112 113 foreach (ver; supportedPre2017Versions) 114 { 115 Key k = windowsGetKeyWithPath("SOFTWARE", "Microsoft", "VisualStudio", ver); 116 try 117 { 118 if(k !is null && k.getValue("InstallDir")) 119 return true; 120 } 121 catch(Exception e){return false;} 122 } 123 return false; 124 } 125 126 private bool installMSLinker(ref Terminal t, ref RealTimeConsoleInput input, TargetVersion ver, Download[] content) 127 { 128 string[] installList = 129 [ 130 "Microsoft.VisualStudio.Workload.VCTools", 131 "Microsoft.VisualStudio.Component.TestTools.BuildTools", 132 "Microsoft.VisualStudio.Component.VC.ASAN", 133 "Microsoft.VisualStudio.Component.VC.Tools.x86.x64" 134 ]; 135 136 import std.algorithm:reduce; 137 138 auto ret = t.wait(spawnShell(content[0].getOutputPath(ver)~" --wait --passive --norestart " ~installList.reduce!((str, last) => "--add "~last~" "~str))) == 0; 139 return ret == 0; 140 } 141 142 143 void initialize() 144 { 145 MSVCLinker = Feature( 146 "MSVCLinker", 147 "Windows SDK for being able to compile using D programming language", 148 ExistenceChecker(null, null, toDelegate(&hasMSVCLinker)), 149 Installation([ 150 Download( 151 DownloadURL( 152 windows: "https://aka.ms/vs/17/release/vs_BuildTools.exe" 153 ), 154 outputPath: "$CWD/buildtools/vc_BuildTools.exe" 155 )], toDelegate(&installMSLinker) 156 ), 157 ); 158 } 159 void start() 160 { 161 162 }